package biblio.model;

import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * Classe qui sert d'abstraction pour une table de hachage (map)
 * La table de hachage peut contenir des instances de la classe revue (ou de ses sous-classes)
 * @param E le type d'objet contenu dans la table de hachage (E doit etendre Revue)
 * @author Groupe 2
 * @version 18/11/13
 */
public class Biblio<E extends Revue> {

	/**La table de hachage triee selon les titres */
	private SortedMap<String, E> titleMap;
	
	/**La table de hachage triee selon les rangs */
	private SortedMap<String, E> rankMap;
	
	/**La table de hachage triee selon les for1 */
	private SortedMap<String, E> for1Map;
	
	/**La table de hachage triee selon les for2 */
	private SortedMap<String, E> for2Map;
	
	/**La table de hachage triee selon les for3 */
	private SortedMap<String, E> for3Map;
	
	/**La table de hachage triee selon les for1name */
	private SortedMap<String, E> for1NameMap;
	
	/**La table de hachage triee selon les for2name */
	private SortedMap<String, E> for2NameMap;
	
	/**La table de hachage triee selon les for3name */
	private SortedMap<String, E> for3NameMap;
	
	/** Constructeur qui initialise la Biblio avec des TreeMaps*/
	public Biblio()
	{
		titleMap = new TreeMap<String, E>();
		rankMap = new TreeMap<String, E>(new RevueComparators().new RankComp());
		for1Map = new TreeMap<String, E>(new RevueComparators().new SimpleStringComp());
		for2Map = new TreeMap<String, E>(new RevueComparators().new SimpleStringComp());
		for3Map = new TreeMap<String, E>(new RevueComparators().new SimpleStringComp());
		for1NameMap = new TreeMap<String, E>(new RevueComparators().new SimpleStringComp());
		for2NameMap = new TreeMap<String, E>(new RevueComparators().new SimpleStringComp());
		for3NameMap = new TreeMap<String, E>(new RevueComparators().new SimpleStringComp());
	}
	
  /** Construit une Biblio qui utilise les tables de hachage ordonnees passees en arguments */
	public Biblio(SortedMap<String, E> titleMap, 
	SortedMap<String, E> rankMap, 
	SortedMap<String, E> for1Map, 
	SortedMap<String, E> for1NameMap, 
	SortedMap<String, E> for2Map, 
	SortedMap<String, E> for2NameMap, 
	SortedMap<String, E> for3Map, 
	SortedMap<String, E> for3NameMap)
	{
		this.titleMap=titleMap; 
		this.rankMap=rankMap;
		this.for1Map=for1Map; 
		this.for1NameMap=for1NameMap;
		this.for2Map=for2Map;
		this.for2NameMap=for2NameMap;
		this.for3Map=for3Map;
		this.for3NameMap=for3NameMap;
	}
   
   /**
    * @pre r!=null
    * @post remplace les variables d'instance de r qui sont null
    * 		par des string vides ""
    */
	private void regularize(E r){
		if(r.getTitre()==null){
			r.setTitre("");
		}
		if(r.getRang()==null){
			r.setRang("");
		}
		if(r.getFor1()==null){
			r.setFor1("");
		}
		if(r.getFor2()==null){
			r.setFor2("");
		}
		if(r.getFor3()==null){
			r.setFor3("");
		}
		if(r.getFor1name()==null){
			r.setFor1name("");
		}
		if(r.getFor2name()==null){
			r.setFor2name("");
		}
		if(r.getFor3name()==null){
			r.setFor3name("");
		}
	}
	
   /**
	* @pre revue != null
	* @post revue a ete rajoute a la bibliotheque this
	* 		les champs null de revue sont mis a ""
	*/
	public void add(E revue)
	{
		regularize(revue);
		titleMap.put(revue.getTitre(),revue);
		rankMap.put(revue.getRang(),revue);
		for1Map.put(revue.getFor1(),revue);
		for1NameMap.put(revue.getFor1name(),revue);
		for2Map.put(revue.getFor2(),revue);
		for2NameMap.put(revue.getFor2name(),revue);
		for3Map.put(revue.getFor3(),revue);
		for3NameMap.put(revue.getFor3name(),revue);
	}
	
   /**
	 * @pre titre!=null
	 * @post retourne la revue associee a titre. Permet de rechercher
	 * 		 les revues a partir d'une partie de titre uniquement.
	 * 		 Exemple : "pol" retrouve "police"
	 */
	public E getByTitle(String titre)
	{
		int i = 0;
		String current=null;
		if (titleMap.get(titre) == null) {
			String[] split;
			for ( String key : titleMap.keySet() ) {
				if (key != null) {
					split = key.split("\\s");
					if (titre.equals(split[0])) {
						current = key;
						i++;
					}
				}
			}
			if (i == 1) 
				return titleMap.get(current);
		}
		return titleMap.get(titre);
	}
	
	 /**
	 * @pre  r!=null
	 * @post retourne la revue dont le rang est r. Permet de rechercher
	 * 		 les revues a partir d'une partie de rang uniquement.
	 * 		 Exemple : "pol" retrouve "police"
	 */
	public E getByRank(String r)
	{
		int i = 0;
		String current=null;
		if (rankMap.get(r) == null) {
			String[] split;
			for ( String key : rankMap.keySet() ) {
				if (key != null) {
					split = key.split("\\s");
					if (r.equals(split[0])) {
						current = key;
						i++;
					}
				}
			}
			if (i == 1) 
				return rankMap.get(current);
		}
		return rankMap.get(r);
	}
	
	/**
	 * @pre  r!=null
	 * @post retourne la revue dont le for1 est r. Permet de rechercher
	 * 		 les revues a partir d'une partie de for1 uniquement.
	 * 		 Exemple : "pol" retrouve "police"
	 */
	public E getByFor1(String r)
	{
		int i = 0;
		String current=null;
		if (for1Map.get(r) == null) {
			String[] split;
			for ( String key : for1Map.keySet() ) {
				if (key != null) {
					split = key.split("\\s");
					if (r.equals(split[0])) {
						current = key;
						i++;
					}
				}
			}
			if (i == 1) 
				return for1Map.get(current);
		}
		return for1Map.get(r);
	}
	
	/**
	 * @pre  r!=null
	 * @post retourne la revue dont le for2 est r. Permet de rechercher
	 * 		 les revues a partir d'une partie de for2 uniquement.
	 * 		 Exemple : "pol" retrouve "police"
	 */
	public E getByFor2(String r)
	{
		int i = 0;
		String current=null;
		if (for2Map.get(r) == null) {
			String[] split;
			for ( String key : for2Map.keySet() ) {
				if (key != null) {
					split = key.split("\\s");
					if (r.equals(split[0])) {
						current = key;
						i++;
					}
				}
			}
			if (i == 1) 
				return for2Map.get(current);
		}
		return for2Map.get(r);
	}
	
	/**
	 * @pre  r!=null
	 * @post retourne la revue dont le for3 est r. Permet de rechercher
	 * 		 les revues a partir d'une partie de for3 uniquement.
	 * 		 Exemple : "pol" retrouve "police"
	 */
	public E getByFor3(String r)
	{
		int i = 0;
		String current=null;
		if (for3Map.get(r) == null) {
			String[] split;
			for ( String key : for3Map.keySet() ) {
				if (key != null) {
					split = key.split("\\s");
					if (r.equals(split[0])) {
						current = key;
						i++;
					}
				}
			}
			if (i == 1) 
				return for3Map.get(current);
		}
		return for3Map.get(r);
	}
	
	/**
	 * @pre  r!=null
	 * @post retourne la revue dont le for1Name est r. Permet de rechercher
	 * 		 les revues a partir d'une partie de for1Name uniquement.
	 * 		 Exemple : "pol" retrouve "police"
	 */
	public E getByFor1Name(String r)
	{
		int i = 0;
		String current=null;
		if (for1NameMap.get(r) == null) {
			String[] split;
			for ( String key : for1NameMap.keySet() ) {
				if (key != null) {
					split = key.split("\\s");
					if (r.equals(split[0])) {
						current = key;
						i++;
					}
				}
			}
			if (i == 1) 
				return for1NameMap.get(current);
		}
		return for1NameMap.get(r);
	}
	
	/**
	 * @pre  r!=null
	 * @post retourne la revue dont le for2Name est r. Permet de rechercher
	 * 		 les revues a partir d'une partie de for2Name uniquement.
	 * 		 Exemple : "pol" retrouve "police"
	 */
	public E getByFor2Name(String r)
	{
		int i = 0;
		String current=null;
		if (for2NameMap.get(r) == null) {
			String[] split;
			for ( String key : for2NameMap.keySet() ) {
				if (key != null) {
					split = key.split("\\s");
					if (r.equals(split[0])) {
						current = key;
						i++;
					}
				}
			}
			if (i == 1) 
				return for2NameMap.get(current);
		}
		return for2NameMap.get(r);
	}
	
	/**
	 * @pre  r!=null
	 * @post retourne la revue dont le for3Name est r. Permet de rechercher
	 * 		 les revues a partir d'une partie de for3Name uniquement.
	 * 		 Exemple : "pol" retrouve "police"
	 */
	public E getByFor3Name(String r)
	{
		int i = 0;
		String current=null;
		if (for3NameMap.get(r) == null) {
			String[] split;
			for ( String key : for3NameMap.keySet() ) {
				if (key != null) {
					split = key.split("\\s");
					if (r.equals(split[0])) {
						current = key;
						i++;
					}
				}
			}
			if (i == 1) 
				return for3NameMap.get(current);
		}
		return for3NameMap.get(r);
	}
	
   /**
	* @pre /
	* @post retourne une liste qui contient les tables de hachages
	*       dont se sert la bibliotheque. Dans l'ordre : titre, rang,
	* 		for1, for1Name, for2, for2Name, for3, for3Name.
	*/
	public List<SortedMap<String, E>> getAllMaps() {
		List<SortedMap<String, E>> ret= new ArrayList<SortedMap<String, E>>();
		ret.add(titleMap);
		ret.add(rankMap);
		ret.add(for1Map);
		ret.add(for1NameMap);
		ret.add(for2Map);
		ret.add(for2NameMap);
		ret.add(for3Map);
		ret.add(for3NameMap);
		return ret;
	}

   /**
	* @pre map != null
	* @post la bibliotheque utilise desormais les tables de hachage 
	* 		ordonnees passees en arguments
	*/
	public void setAllMaps(SortedMap<String, E> titleMap, 
	SortedMap<String, E> rankMap, 
	SortedMap<String, E> for1Map, 
	SortedMap<String, E> for1NameMap, 
	SortedMap<String, E> for2Map, 
	SortedMap<String, E> for2NameMap, 
	SortedMap<String, E> for3Map, 
	SortedMap<String, E> for3NameMap)
	{
		this.titleMap=titleMap; 
		this.rankMap=rankMap;
		this.for1Map=for1Map; 
		this.for1NameMap=for1NameMap;
		this.for2Map=for2Map;
		this.for2NameMap=for2NameMap;
		this.for3Map=for3Map;
		this.for3NameMap=for3NameMap;
	}
	
	/**
	 * @pre /
	 * @post retourne une liste des revues triees par titre
	 */
	public List<E> listByTitle(){
		ArrayList<E> r=new ArrayList<E>(titleMap.values());
		return r;
	}
	
	/**
	 * @pre /
	 * @post retourne une liste des revues triees par rang
	 */
	public List<E> listByRank(){
		ArrayList<E> r=new ArrayList<E>(rankMap.values());
		return r;
	}
	
	/**
	 * @pre /
	 * @post retourne une liste des revues triees par for1
	 */
	public List<E> listByFor1(){
		ArrayList<E> r=new ArrayList<E>(for1Map.values());
		return r;
	}
	
	/**
	 * @pre /
	 * @post retourne une liste des revues triees par for1Name
	 */
	public List<E> listByFor1Name(){
		ArrayList<E> r=new ArrayList<E>(for1NameMap.values());
		return r;
	}
	
	/**
	 * @pre /
	 * @post retourne une liste des revues triees par for2
	 */
	public List<E> listByFor2(){
		ArrayList<E> r=new ArrayList<E>(for2Map.values());
		return r;
	}
	
	/**
	 * @pre /
	 * @post retourne une liste des revues triees par for2Name
	 */
	public List<E> listByFor2Name(){
		ArrayList<E> r=new ArrayList<E>(for2NameMap.values());
		return r;
	}
	
	/**
	 * @pre /
	 * @post retourne une liste des revues triees par for3
	 */
	public List<E> listByFor3(){
		ArrayList<E> r=new ArrayList<E>(for3Map.values());
		return r;
	}
	
	/**
	 * @pre /
	 * @post retourne une liste des revues triees par for3Name
	 */
	public List<E> listByFor3Name(){
		ArrayList<E> r=new ArrayList<E>(for3NameMap.values());
		return r;
	}
}
